其他
Java 泛型背后的原理是什么?
1,《往期精选优秀博文都在这里了!》 2、呕心沥血总结的14张思维导图,教你构建 Python核心知识体系(附高清下载) 3、一份来自亚马逊技术专家的Google面试指南,GitHub收获9.8万星,已翻译成中文 4、支付宝系统架构(内部架构图) 5、牛逼!IDEA 2020 要本土化,真的是全中文了!中国开发者话语权越来越大了
那可不可以往List集合中添加多个类型的数据呢,答案是可以的,其实我们可以把list集合当成普通的类也是没问题的,那么就有下面的代码:
从这里可以看出来,不定义泛型也是可以往集合中添加数据的,所以说泛型只是一种类型的规范,在代码编写阶段起一种限制。
public class BaseBean<T> {
T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
extends
,对于泛型写得多的伙伴们来说,extends
是约束了泛型是向下继承的,最后我们通过反射获取value的类型是String类型的,因此这里也不难看出,加extends
关键字其实最终目的是约束泛型是属于哪一类的。所以我们在编写代码的时候如果没有向下兼容类型,会警告错误的:大家有没有想过为啥要用泛型呢,既然说了泛型其实对于jvm来说都是Object类型的,那咱们直接将类型定义成Object不就是的了,这种做法是可以,但是在拿到Object类型值之后,自己还得强转,因此泛型减少了代码的强转工作,而将这些工作交给了虚拟机。
势必在getValue的时候代码有个强转的过程,因此在能用泛型的时候,尽量用泛型来写,而且我认为一个好的架构师,业务的抽取是离不开泛型的定义。
常见的泛型主要有作用在普通类上面,作用在抽象类、接口、静态或非静态方法上。
比如实际项目中,我们经常会遇到服务端返回的接口中都有 errMsg
、status
等公共返回信息,而变动的数据结构是data信息,因此我们可以抽取公共的BaseBean
:
public class BaseBean<T> {
public String errMsg;
public T data;
public int status;
}
//抽象类泛型
public abstract class BaseAdapter<T> {
List<T> DATAS;}//接口泛型public interface Factory<T> {
T create();
}
//方法泛型
public static <T> T getData() {
return null;
}
public interface Base<K, V> {
void setKey(K k);
V getValue();}
public interface BaseCommon<K extends Common1, V> extends Base<K, V> {
}
//或抽象类
public abstract class BaseCommon<K extends Common1, V>
implements Base<K, V> {
}
public interface Base<K, V> {
// void setKey(K k);//// V getValue();
void addNode(Map<K, V> map);
Map<K, V> getNode(int index);}public abstract class BaseCommon<K, V> implements Base<K, V> {
//多重泛型
LinkedList<Map<K, V>> DATAS = new LinkedList<>();
@Override
public void addNode(Map<K, V> map) {
DATAS.addLast(map);
}
@Override
public Map<K, V> getNode(int index) {
return DATAS.get(index);
}
}
通配符 <?>通配符
和<T>
区别是在你不知道泛型类型的时候,可以用通配符来定义,下面通过一个例子来看看的用处:
//定义了一个普通类
public class BaseBean<T> {
T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
//用来定义泛型的
public class Common1 extends Common {
}
在定义的时候将Common的泛型指向Common1的泛型,可以看到直接提示有问题,这里可以想,虽然Common1是继承自Common的,但是并不代表BaseBean之间是等量的。
public static void main(String\[\] args) {
BaseBean<Common> commonBaseBean = new BaseBean<>();
//通配符定义就没有问题
BaseBean<?> common1BaseBean = commonBaseBean;
try {
//通过反射猜测setValue的参数是Object类型的
Method setValue = common1BaseBean.getClass().getDeclaredMethod("setValue", Object.class);
setValue.invoke(common1BaseBean, "123");
Object value = common1BaseBean.getValue();
System.out.println("result:" + value);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
通配符不能定义在类上面、接口或方法上,只能作用在方法的参数上
其他的几种情况自己去尝试,正确的使用通配符:
public void setClass(Class<?> class){
//todo
}
<T extends>表示上限泛型、<T super>表示下限泛型
//新增加的一个
BaseCommonpublic class Common extends BaseCommon{}
第二个定义的泛型是不合法的,因为BaseCommon是Common的父类,超出了Common的类型范围。10 道泛型面试题,推荐你看下。
在BaseBean里面定义了个方法:
public void add(Class<? super Common> clazz) {}
在实际开发中其实知道什么时候定义什么类型的泛型就ok,在mvp实际案例中泛型用得比较广泛,大家可以根据实际项目来找找泛型的感觉,只是面试的时候需要理解类型擦除是针对谁而言的。关注微信公众号:互联网架构师,获取更多架构技术干货。
类型擦除
https://www.jianshu.com/p/dd34211f2565
另:公众号后台回复【2T】有惊喜礼包!
1.不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事
4.“37岁,985毕业,年薪50万,被裁掉只用了10分钟”
5.37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...